package com.gf.framework.web.exception;

import com.gf.framework.common.exception.BizException;
import com.gf.framework.common.result.BaseResultCodeEnum;
import com.gf.framework.common.result.R;
import com.gf.framework.common.utils.SpringContextUtil;
import com.gf.framework.common.utils.list.GfArrayList;
import com.gf.framework.common.utils.list.GfList;
import lombok.extern.slf4j.Slf4j;
import org.springframework.core.annotation.Order;
import org.springframework.validation.FieldError;
import org.springframework.validation.ObjectError;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;

import java.util.List;

/**
 * @author liao
 */
@Slf4j
@ControllerAdvice
@Order(100)
public class GlobalExceptionHandler {

    @ResponseBody
    @ExceptionHandler(Exception.class)
    public R<Object> exception(Exception exception) {
        log.error("系统异常", exception);
        return R.fail(BaseResultCodeEnum.SYSTEM_ERROR, getErrorMsgByEnvironment(exception));
    }

//    @ResponseBody
//    @ExceptionHandler(RpcException.class)
//    public ResultWrapper<Object> rpcException(RpcException rpcException) {
//        log.error("dubbo调用异常", rpcException);
//        return ResultWrapper.fail(BaseResultCodeEnum.SYSTEM_ERROR, "dubbo调用异常:" + rpcException.getMessage());
//    }

    @ResponseBody
    @ExceptionHandler(org.springframework.dao.DuplicateKeyException.class)
    public R<Object> exception(org.springframework.dao.DuplicateKeyException exception) {
        log.error("重复写入", exception);
        return R.fail(BaseResultCodeEnum.RESOURCE_ALREADY_EXIST.getCode(), exception.getCause().getMessage());
    }

    @ResponseBody
    @ExceptionHandler(BizException.class)
    public R<Object> bizException(BizException bizException) {
        log.warn("业务异常 id:{} message:{}", bizException.getCode(), bizException.getMessage());
        return R.fail(bizException.getCode(), bizException.getMsg());
    }

    @ResponseBody
    @ExceptionHandler(MethodArgumentNotValidException.class)
    public R<Object> methodArgumentNotValidException(MethodArgumentNotValidException methodArgumentNotValidException) {
        List<ObjectError> allErrors = methodArgumentNotValidException.getBindingResult().getAllErrors();
        GfList<String> errorArr = new GfArrayList<String>().addAll(allErrors, error -> {
            if (error instanceof FieldError) {
                FieldError fieldError = (FieldError) error;
                return fieldError.getField() + fieldError.getDefaultMessage();
            } else {
                return error.getDefaultMessage();
            }
        });

        String errMsg = String.join(" ", errorArr.toArray(new String[]{}));
        return R.fail(BaseResultCodeEnum.ILLEGAL_ARGUMENT.getCode(), errMsg);
    }

    private String getErrorMsgByEnvironment(Exception exception) {
        StringBuilder errorMsg = new StringBuilder();
        if (SpringContextUtil.isDev() || SpringContextUtil.isTest() || SpringContextUtil.isProd()) {
            errorMsg.append(exception.toString());
            for (StackTraceElement stackTraceElement : exception.getStackTrace()) {
                // 将堆栈信息中第一个业务代码的位置显示出来
                if (stackTraceElement.toString().contains("com.gf")) {
                    errorMsg.append(stackTraceElement);
                    break;
                }
            }
        }
        return errorMsg.toString();
    }

}
